home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 43 / Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso / -serious- / comms / other / amivnc / amivnc.c < prev    next >
C/C++ Source or Header  |  1999-06-14  |  40KB  |  980 lines

  1. // AmiVNC - Amiga experimental VNC server - Protocol ORL version 3.3
  2.  
  3. // Includes ***********************************************
  4. // Needed to compile : SDK Cybergraphx 4.1 & SDK AmiTCP 4.3
  5. #include <exec/types.h>
  6. #include <exec/memory.h>
  7. #include <devices/input.h>
  8. #include <devices/inputevent.h>
  9. #include <libraries/commodities.h>
  10. #include <proto/all.h>
  11. #include <proto/socket.h>
  12.  
  13. #include <cybergraphx/cybergraphics.h>
  14. #include <proto/cybergraphics.h>
  15.  
  16. #include <dos/dostags.h>
  17. #include <sys/socket.h>
  18. #include <sys/ioctl.h>
  19. #include <netinet/in.h>
  20. #include <netdb.h>
  21.  
  22. #include <intuition/intuitionbase.h>
  23. #include <intuition/intuition.h>
  24. #include <graphics/displayinfo.h>
  25. #include <graphics/gfxbase.h>
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include <fcntl.h>
  32. #include <ctype.h>
  33.  
  34. // Specific Inculdes ***********************************************
  35. #include "rfbproto.h"                   // Structures & constants for VNC protocol
  36. #include "vncauth.h"                    // Prototypes for authentication
  37.  
  38. // Constants ***********************************************
  39. #define XDC_PORT 5900                   // Port # for bind()
  40. #define FALSE 0
  41. #define TRUE 1
  42. #define XDC_TILE 32                     // Tile size
  43.  
  44. #define XDC_C_VBUF      (1L << 0)
  45. #define XDC_C_MSOCK     (1L << 1)
  46. #define XDC_C_CSOCK     (1L << 2)
  47.  
  48. #define XDC_C_MAXDEPTH  4               // Max. raster depth : 4 bytes / pixel
  49.  
  50. #undef PARANO
  51.  
  52. // Common messages
  53. char XDC_ID[] = "AmiVNC 0.0.11b4 May 28 1999";
  54. char XDC_SEND[] = "main.c / main : send() error";
  55. char XDC_RECV[] = "main.c / main : recv() error";
  56.  
  57. // Global variables ***********************************************
  58. LONG    iDuplicateSocketKey;            // Client socket key for transmitting to child process
  59. ULONG   uOpened = NULL;                 // Opened resources, to be closed on exit
  60. BOOL    bDie = FALSE, *pDie = &bDie;    // TRUE : processes are to exit (Argh, very trashy)
  61. char    cPassword[MAXPWLEN + 1];
  62. LONG    iMasterSocket,                  // Listening socket for incoming connections
  63.         iClientSocket;                  // Client socket accept()ed
  64. UBYTE   *pBuffer = NULL;                // Reference buffer for screen change detection
  65. char    *sPWFile = "S:AmiVNC.pwd";      // Password file name
  66.  
  67. // Free all resources allocated to a client session ***********************************************
  68. void vCleanSession(char *cMsg, long lCode)
  69. {
  70.     // Tell the child process to exit (as we are the main process,
  71.     // we can use bDie, which is in our address space)
  72.     if (!bDie)
  73.     {
  74.         bDie = TRUE;
  75.         Delay(125);
  76.     }
  77.     
  78.     // Close everything opened
  79.     if (uOpened & XDC_C_VBUF) free(pBuffer);
  80.     if (uOpened & XDC_C_CSOCK) CloseSocket(iClientSocket);
  81.     
  82.     printf("AmiVNC - %s (%ld)\nAmiVNC session closed\n", cMsg, lCode);
  83. }
  84.  
  85. // Free all resources allocated to main process and exit ***********************************************
  86. void vCleanExit(char *cMsg, long lCode)
  87. {
  88.     vCleanSession(cMsg, lCode);
  89.     
  90.     if (uOpened & XDC_C_MSOCK) CloseSocket(iMasterSocket);
  91.     
  92.     printf("AmiVNC halted\n");
  93.     
  94.     exit(0L);
  95. }
  96.  
  97. // Authentication ***********************************************
  98. BOOL bAuthentify(void)
  99. {
  100.         char cChallenge[16], cResponse[16];
  101.         CARD32 c32Value;
  102.         BOOL bAuthenticated = TRUE;
  103.         int iCnt, iFile;
  104.  
  105.         // Read encoded password in s:AmiVNC.pwd
  106.         if (!(iFile = open(sPWFile, O_RDONLY, 0)))
  107.            return(FALSE);
  108.                 
  109.         iCnt = read(iFile, cPassword, sizeof(cPassword));
  110.         
  111.         close(iFile);
  112.         
  113.         if (iCnt != sizeof(cPassword))
  114.            return(FALSE);
  115.  
  116.         // Decode password
  117.         vncDecryptPasswd(cPassword, cPassword);
  118.         
  119.         // Authenticate the connection, if required
  120.         if (!strlen(cPassword))
  121.         {
  122.                 // Send no-auth-required message
  123.                 c32Value = rfbNoAuth;
  124.                 if (!(-1 == (send(iClientSocket,(char *)&c32Value, sizeof(c32Value), 0))))
  125.                         return FALSE;
  126.  
  127.                 return(TRUE);
  128.         }
  129.         else
  130.         {
  131.                 // Send auth-required message
  132.                 c32Value = rfbVncAuth;
  133.                 if (-1 == (send(iClientSocket,(char *)&c32Value, sizeof(c32Value), 0)))
  134.                         return FALSE;
  135.  
  136.                 // Now create a 16-byte challenge
  137.                 vncRandomBytes((BYTE *)cChallenge);
  138.  
  139.                 // Send the challenge to the client
  140.                 if (-1 == (send(iClientSocket, cChallenge, sizeof(cChallenge), 0)))
  141.                         return FALSE;
  142.  
  143.                 // Read the response
  144.                 if (-1 == (recv(iClientSocket, cResponse, sizeof(cResponse), 0)))
  145.                         return FALSE;
  146.  
  147.                 // Encrypt the challenge bytes
  148.                 vncEncryptBytes((BYTE *)cChallenge, cPassword);
  149.  
  150.                 // Compare them to the response
  151.                 for (iCnt = 0; iCnt < sizeof(cChallenge); iCnt++)
  152.                 {
  153.                         if (cChallenge[iCnt] != cResponse[iCnt])
  154.                         {
  155.                                 bAuthenticated = FALSE;
  156.                                 break;
  157.                         }
  158.                 }
  159.  
  160.                 // Did the authentication work?
  161.                 if (!bAuthenticated)
  162.                 {
  163.                         c32Value = rfbVncAuthFailed;
  164.                         send(iClientSocket, (char *)&c32Value, sizeof(c32Value), 0);
  165.                         return FALSE;
  166.  
  167.                 }
  168.                 else
  169.                 {
  170.                         // Tell the client we're ok
  171.                         c32Value = rfbVncAuthOK;
  172.                         if (-1 == (send(iClientSocket, (char *)&c32Value, sizeof(c32Value), 0)))
  173.                                 return FALSE;
  174.                 
  175.                         return(TRUE);
  176.                 }
  177.         }
  178. }
  179.  
  180. // Incoming messages management thread ***********************************************
  181. void __saveds vProcessIncomes(void)
  182. {
  183.     struct IOStdReq *inputReqBlk;
  184.     struct MsgPort *inputPort;
  185.     struct InputEvent eEvent, *VNCEvent = &eEvent;
  186.     UWORD uQualifier = 0;
  187.     rfbClientToServerMsg sCMsg;
  188.     BOOL bLClick = FALSE, bMClick = FALSE, bRClick = FALSE;
  189.     struct Library *SocketBase;
  190.     LONG iSocketChild;
  191.  
  192.     // We have to reopen bsdsocket.library, because it can not be shared between processes
  193.     // OpenLibrary can not fail since it would have halted the father before creating us.
  194.     SocketBase = OpenLibrary("bsdsocket.library", 4L);
  195.  
  196.     // Obtain the client socket descriptor from the key saved for us by our father
  197.     if (-1 == (iSocketChild = ObtainSocket(iDuplicateSocketKey, AF_INET, SOCK_STREAM, 0)))
  198.     {
  199.         printf("main.c / vProcessIncomes : ObtainSocket() error %d\n", Errno());
  200.         *pDie = TRUE;
  201.         goto _Nosock;
  202.     }
  203.     
  204.     printf("main.c / vProcessIncomes runs on socket %d\n", iSocketChild);
  205.  
  206.     // Create input.device message structure
  207.     inputPort = CreatePort(NULL, NULL);
  208.     inputReqBlk = (struct IOStdReq *) CreateExtIO(inputPort, sizeof(struct IOStdReq));
  209.     OpenDevice("input.device", NULL, (struct IORequest *) inputReqBlk, NULL);
  210.     inputReqBlk -> io_Data = (APTR) VNCEvent;
  211.     inputReqBlk -> io_Command = IND_WRITEEVENT;
  212.     inputReqBlk -> io_Flags = 0;
  213.     inputReqBlk -> io_Length = sizeof(struct InputEvent);
  214.     
  215.     // Process incoming messages until main process tells to die.
  216.     // Use pointer to bDie because it is not in our address space...
  217.     while (!*pDie) // VERY VERY dirty way to know we have to exit...
  218.     {
  219.        if (-1 == recv(iSocketChild, (UBYTE *) &sCMsg, 1, 0))
  220.        {
  221.            printf("main.c / vProcessIncomes : recv() error, errno = %d\n", Errno());
  222.            *pDie  = TRUE;
  223.            continue;
  224.        }
  225.        
  226.        Forbid(); // Leave us handle properly our input event
  227.        switch(sCMsg.type)
  228.        {
  229.            case rfbSetPixelFormat : // 0
  230.            if (sz_rfbSetPixelFormatMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbSetPixelFormatMsg - 1, 0))
  231.            {
  232. #ifdef PARANO
  233.                printf("C -> S : rfbSetPixelFormat lanbpp %d depth %d bigE %d tc %d redM %d redS %d GreM %d GreS %d BluM %d BluS %d\n",
  234.                   sCMsg.spf.format.bitsPerPixel,
  235.                   sCMsg.spf.format.depth,
  236.                   sCMsg.spf.format.bigEndian,
  237.                   sCMsg.spf.format.trueColour,
  238.                   sCMsg.spf.format.redMax,
  239.                   sCMsg.spf.format.redShift,
  240.                   sCMsg.spf.format.greenMax,
  241.                   sCMsg.spf.format.greenShift,
  242.                   sCMsg.spf.format.blueMax,
  243.                   sCMsg.spf.format.blueShift
  244.                   );
  245. #endif // PARANO
  246.                break;
  247.            }
  248.            
  249.            case rfbFixColourMapEntries : // 1
  250.            if (sz_rfbFixColourMapEntriesMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbFixColourMapEntriesMsg - 1, 0))
  251.            {
  252. #ifdef PARANO
  253.                printf("C -> S : rfbFixColourMapEntries\n");
  254. #endif // PARANO
  255.                break;
  256.            }
  257.            
  258.            case rfbSetEncodings : // 2
  259.            if (sz_rfbSetEncodingsMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbSetEncodingsMsg - 1, 0))
  260.            {
  261. #ifdef PARANO
  262.                printf("C -> S : rfbSetEncodings\n");
  263. #endif // PARANO
  264.                break;
  265.            }
  266.            
  267.            case rfbFramebufferUpdateRequest : // 3
  268.            if (sz_rfbFramebufferUpdateRequestMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbFramebufferUpdateRequestMsg - 1, 0))
  269.            {
  270. #ifdef PARANO            
  271.                printf("C -> S : rfbFramebufferUpdateRequest inc %d x %d y %d w %d h %d\n",
  272.                   sCMsg.fur.incremental,
  273.                   sCMsg.fur.x,
  274.                   sCMsg.fur.y,
  275.                   sCMsg.fur.w,
  276.                   sCMsg.fur.h
  277.                   );
  278. #endif // PARANO            
  279.                break;
  280.            }
  281.            
  282.            case rfbKeyEvent : // 4
  283.            if (sz_rfbKeyEventMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbKeyEventMsg - 1, 0))
  284.            {
  285. #ifdef PARANO
  286.                printf("C -> S : rfbKeyEvent down %d key %d ('%c')\n",
  287.                   sCMsg.ke.down,
  288.                   sCMsg.ke.key,
  289.                   sCMsg.ke.key
  290.                  );
  291. #endif // PARANO
  292.                // Process special keys
  293.                if ((sCMsg.ke.down) && (0xFFE0 == (sCMsg.ke.key & 0xFFE0)))
  294.                {
  295.                    if (sCMsg.ke.key == 0xFFE1) uQualifier |= IEQUALIFIER_LSHIFT;  // Left Shift
  296.                    if (sCMsg.ke.key == 0xFFE2) uQualifier |= IEQUALIFIER_RSHIFT;  // Right Shift
  297.                    if (sCMsg.ke.key == 0xFFE3) uQualifier |= IEQUALIFIER_CONTROL; // Left Control
  298.                    if (sCMsg.ke.key == 0xFFE4) uQualifier |= IEQUALIFIER_CONTROL; // Right Control
  299.                    if (sCMsg.ke.key == 0xFFE9) uQualifier |= IEQUALIFIER_LALT;    // Left Alt
  300.                    if (sCMsg.ke.key == 0xFFEA) uQualifier |= IEQUALIFIER_RALT;    // Right Alt
  301.                    break;
  302.                }
  303.                if ((!sCMsg.ke.down) && (0xFFE0 == (sCMsg.ke.key & 0xFFE0)))
  304.                {
  305.                    if (sCMsg.ke.key == 0xFFE1) uQualifier &= ~IEQUALIFIER_LSHIFT; // Left Shift
  306.                    if (sCMsg.ke.key == 0xFFE2) uQualifier &= ~IEQUALIFIER_RSHIFT; // Right Shift
  307.                    if (sCMsg.ke.key == 0xFFE3) uQualifier &= ~IEQUALIFIER_CONTROL; // Left Control
  308.                    if (sCMsg.ke.key == 0xFFE4) uQualifier &= ~IEQUALIFIER_CONTROL; // Right Control
  309.                    if (sCMsg.ke.key == 0xFFE9) uQualifier &= ~IEQUALIFIER_LALT;    // Left Alt
  310.                    if (sCMsg.ke.key == 0xFFEA) uQualifier &= ~IEQUALIFIER_RALT;    // Right Alt
  311.                    break;
  312.                }
  313.  
  314.                // Do nothing on key release
  315.                if (!sCMsg.ke.down) break;
  316.  
  317.                // Process cursor-related keys
  318.                if (0xFF50 == (sCMsg.ke.key & 0xFF50))
  319.                {
  320.                    VNCEvent -> ie_Class = IECLASS_RAWKEY;
  321.                    VNCEvent -> ie_Qualifier = 0;
  322.                    switch(sCMsg.ke.key & 0x000F)
  323.                    {
  324.                        case 0 : // Home
  325.                            VNCEvent -> ie_Code = 0x3D;
  326.                            break;
  327.                        case 1 : // Left
  328.                            VNCEvent -> ie_Code = 0x4F;
  329.                            break;
  330.                        case 2 : // Up
  331.                            VNCEvent -> ie_Code = 0x4C;
  332.                            break;
  333.                        case 3 : // Right
  334.                            VNCEvent -> ie_Code = 0x4E;
  335.                            break;
  336.                        case 4 : // Down
  337.                            VNCEvent -> ie_Code = 0x4D;
  338.                            break;
  339.                        case 5 : // Page up
  340.                            VNCEvent -> ie_Code = 0x3F;
  341.                            break;
  342.                        case 6 : // Page down
  343.                            VNCEvent -> ie_Code = 0x1F;
  344.                            break;
  345.                        case 7 : // End
  346.                            VNCEvent -> ie_Code = 0x1D;
  347.                            break;
  348.                        default :
  349.                            break;
  350.                    }
  351.                }
  352.                else
  353.                {
  354.                    // Map out other 0xFF'ed keys
  355.                    sCMsg.ke.key &= 0xFF;
  356.                    
  357.                    // Find rawkey event out of key ; if we can not, reject key
  358.                    if (!InvertKeyMap((ULONG) sCMsg.ke.key, VNCEvent, NULL))
  359.                    break;
  360.                }
  361.                
  362.                // Apply qualifier if possible
  363.                if (!strchr("~`£µ¨", (int) sCMsg.ke.key)) switch(uQualifier)
  364.                {
  365.                    case IEQUALIFIER_CONTROL :
  366.                    case IEQUALIFIER_LSHIFT :
  367.                    case IEQUALIFIER_RSHIFT :
  368.                        VNCEvent -> ie_Qualifier = uQualifier;
  369.                        break;
  370.                            
  371.                    case IEQUALIFIER_LALT :
  372.                        VNCEvent -> ie_Qualifier = IEQUALIFIER_LCOMMAND;
  373.                        break;
  374.                            
  375.                    case IEQUALIFIER_RALT | IEQUALIFIER_CONTROL :
  376.                        VNCEvent -> ie_Qualifier = IEQUALIFIER_RCOMMAND;
  377.                        break;
  378.                }
  379.                
  380.                // Send key into input.device
  381.                DoIO((struct IORequest *) inputReqBlk);
  382.            break;
  383.            }
  384.            
  385.            case rfbPointerEvent : // 5
  386.            if (sz_rfbPointerEventMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbPointerEventMsg - 1, 0))
  387.            {
  388. #ifdef PARANO
  389.                printf("C -> S : rfbPointerEvent button %d x %d y %d\r",
  390.                   sCMsg.pe.buttonMask,
  391.                   sCMsg.pe.x,
  392.                   sCMsg.pe.y
  393.                  );
  394. #endif // PARANO
  395.                VNCEvent -> ie_NextEvent = NULL;
  396.                VNCEvent -> ie_Class = IECLASS_POINTERPOS;
  397.                VNCEvent -> ie_Qualifier = uQualifier;
  398.                
  399.                // Process mouse X & Y
  400.                VNCEvent -> ie_X = sCMsg.pe.x;
  401.                VNCEvent -> ie_Y = sCMsg.pe.y;
  402.  
  403.                // Process mouse buttons...
  404.                VNCEvent -> ie_Code = IECODE_NOBUTTON;
  405.                
  406.                // Left button
  407.                if ((sCMsg.pe.buttonMask) & 1)
  408.                switch(bLClick)
  409.                {
  410.                    case FALSE : bLClick = TRUE; VNCEvent -> ie_Code = IECODE_LBUTTON; uQualifier |= IEQUALIFIER_LEFTBUTTON; break;
  411.                    case TRUE : VNCEvent -> ie_Code = IECODE_NOBUTTON; break;
  412.                }
  413.                else if (bLClick) { bLClick = FALSE; VNCEvent -> ie_Code = IECODE_LBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_LEFTBUTTON; }
  414.  
  415.                // Middle button
  416.                if ((sCMsg.pe.buttonMask) & 2)
  417.                switch(bMClick)
  418.                {
  419.                    case FALSE : bMClick = TRUE; VNCEvent -> ie_Code = IECODE_MBUTTON;  uQualifier |= IEQUALIFIER_MIDBUTTON; break;
  420.                    case TRUE : VNCEvent -> ie_Code = IECODE_NOBUTTON; break;
  421.                }
  422.                else if (bMClick) { bMClick = FALSE; VNCEvent -> ie_Code = IECODE_MBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_MIDBUTTON; }
  423.  
  424.                // Right button
  425.                if ((sCMsg.pe.buttonMask) & 4)
  426.                switch(bRClick)
  427.                {
  428.                    case FALSE : bRClick = TRUE; VNCEvent -> ie_Code = IECODE_RBUTTON;  uQualifier |= IEQUALIFIER_RBUTTON; break;
  429.                    case TRUE : VNCEvent -> ie_Code = IECODE_NOBUTTON; break;
  430.                }
  431.                else if (bRClick) { bRClick = FALSE; VNCEvent -> ie_Code = IECODE_RBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_RBUTTON; }
  432.  
  433.                // Insert event into input.device stream
  434.                DoIO((struct IORequest *) inputReqBlk);
  435.                break;
  436.            }
  437.            
  438.            case rfbClientCutText : // 6
  439.            if (sz_rfbClientCutTextMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbClientCutTextMsg - 1, 0))
  440.            {
  441.                char *cText = malloc((size_t) (sCMsg.cct.length + 1));
  442.                recv(iSocketChild, cText, sCMsg.cct.length, 0);
  443.                cText[sCMsg.cct.length] = 0;
  444. #ifdef PARANO
  445.                printf("C -> S : rfbClientCutText '%s'\n", cText);
  446. #endif // PARANO
  447.                break;
  448.            }
  449.            
  450.            default :
  451. #ifdef PARANO
  452.            printf("main.c / vProcessIncomes : msg type %d unknown\n", sCMsg.type);
  453. #endif // PARANO
  454.            break;
  455.        }
  456.        Permit();
  457.     }
  458.     
  459.     CloseSocket(iSocketChild);
  460.  
  461.     if (inputReqBlk)
  462.     {
  463.         CloseDevice((struct IORequest *) inputReqBlk);
  464.         DeleteExtIO((struct IORequest *) inputReqBlk);
  465.     }
  466.     
  467.     if (inputPort) DeletePort(inputPort);
  468.  
  469. _Nosock:
  470.     CloseLibrary(SocketBase);
  471.     printf("main.c / vProcessIncomes halted\n");   
  472. }
  473.  
  474. // Main entry point  ***********************************************
  475. int main(int argc, char **argv)
  476. {
  477.     register int iCnt, jCnt;
  478.     int iMajor, iMinor, iWidth, iHeight, iDepth, iSize, iMode, iPort, iRShift = 8, iGShift = 16, iBShift = 24;
  479.     unsigned long uLimit = 0xFFFFFFFF, uSize, uCnt;
  480.     struct sockaddr_in sAddr;                  // Local address for bind()
  481.     struct Screen *pActiveScreen;
  482.     rfbProtocolVersionMsg mProtVerMsg;
  483.     rfbServerInitMsg mSerInitMsg;
  484.     rfbFramebufferUpdateMsg mFBUpdMsg;
  485.     rfbFramebufferUpdateRectHeader mFBRMsg;
  486.     CARD8 c8;
  487.     BOOL bBig = FALSE, bFast;
  488.     struct Library *CGXlib = OpenLibrary("cgxsystem.library", 40L);
  489.     register UBYTE *pRaster;                    // True WB screen raster
  490.     static UBYTE uTile[XDC_TILE * XDC_TILE * XDC_C_MAXDEPTH];    // 3 Byte/pixel RGB Raster tile for client screen updates
  491.     
  492.     // Welcome...
  493.     printf("%s\n(c) 1999 stephane.guillard@steria.fr\n", XDC_ID);
  494.     printf("Options :\n -p<pwd> to store password\n");
  495.     printf(" -s<port> to set listen port (default %d)\n", XDC_PORT);
  496.     printf(" -e to force big endian (default little)\n");
  497.     printf(" -l<size> to limit net block size (default unlimited\n");
  498.     printf(" -(r|g|b)<value> to force color encoding r|g|b bitshift (defaults 8|16|24)\n");
  499.     
  500.     iPort = XDC_PORT;
  501.     
  502.     // Process command line arguments (if any)
  503.     if (argc > 1) while (*++argv)
  504.     {
  505.         char *pC;
  506.         
  507.         switch(tolower((*argv)[1]))
  508.         {
  509.             // *** Force password change and exit
  510.             case 'p' :
  511.                 strncpy(cPassword, *argv + 2, MAXPWLEN);
  512.                 cPassword[MAXPWLEN] = '\0';
  513.                 
  514.                 pC = strchr(cPassword, ' ');
  515.                 if (pC) *pC = '\0';
  516.                 
  517.                 for (iCnt = strlen(cPassword) ; iCnt < MAXPWLEN ; iCnt++)
  518.                    cPassword[iCnt] = '\0';
  519.                 
  520.                 vncEncryptPasswd(cPassword, cPassword);
  521.                 
  522.                 if (-1 == (iCnt = creat(sPWFile, S_IREAD | S_IWRITE)))
  523.                     vCleanExit("main.c / main : creat('s:AmiVNC.pwd') error", 0);
  524.                 write(iCnt, cPassword, sizeof(cPassword));
  525.                 close(iCnt);
  526.                 
  527.                 vCleanExit("main.c / main : Passwd stored", 0);
  528.                 break;
  529.             
  530.             // *** Force another port than the default 5900
  531.             case 's' :
  532.                 iPort = atoi(*argv + 2);
  533.                 break;
  534.             
  535.             // *** Force BigEndian flag in mSerInitMsg
  536.             case 'e' :
  537.                 bBig = TRUE;
  538.                 break;
  539.             
  540.             // *** Limit netblocksize for initial screen update
  541.             case 'l' :
  542.                 uLimit = atoi(*argv + 2);
  543.                 break;
  544.                 
  545.             // *** Force Red / Green / Blue bitshifts in mSerInitMsg
  546.             // (play with this if you have color problems, legal values
  547.             // for shifts are 0, 8, 16 and 24)
  548.             case 'r' :
  549.                 iRShift = atoi(*argv + 2);
  550.                 break;
  551.                 
  552.             case 'g' :
  553.                 iGShift = atoi(*argv + 2);
  554.                 break;
  555.                 
  556.             case 'b' :
  557.                 iBShift = atoi(*argv + 2);
  558.                 break;
  559.                 
  560.             default :
  561.                 printf("main.c / main : Arg [%s] ignored\n", *argv);
  562.                 break;
  563.         }
  564.     }
  565.     
  566.     // Print configurable parameter values
  567.     printf("main.c / main : parameter values :\n");
  568.     printf(" - listen port set to %d\n", iPort);
  569.     printf(" - endian set to %s\n", bBig ? "big" : "little");
  570.     printf(" - initial xfer limit set to %ul\n", uLimit);
  571.     printf(" - color bitshifts : red %d, green %d, blue %d\n", iRShift, iGShift, iBShift);
  572.     
  573.     // Prepare listener socket
  574.     printf("main.c / main : Creating listener socket\n");
  575.     if (-1 == (iMasterSocket = socket(AF_INET, SOCK_STREAM, 0)))
  576.         vCleanExit("main.c / main : socket() error", Errno());
  577.     
  578.     uOpened |= XDC_C_MSOCK;
  579.     
  580.     sAddr.sin_family=AF_INET;
  581.     sAddr.sin_addr.s_addr = 0;
  582.     sAddr.sin_port = htons(iPort);
  583.     
  584.     printf("main.c / main : Binding socket on port %d\n", sAddr.sin_port);
  585.     if (-1 == (bind(iMasterSocket, (struct sockaddr *) &sAddr, sizeof(sAddr))))
  586.         vCleanExit("main.c / main : bind() error", Errno());
  587.     
  588.     printf("main.c / main : Listening set on port %d\n", sAddr.sin_port);
  589.     if (-1 == (listen(iMasterSocket, 4)))
  590.         vCleanExit("main.c / main : listen() error", Errno()); 
  591.  
  592. _NewSession:
  593.  
  594.     bDie = FALSE;
  595.     
  596.     // Wait for incoming connections
  597.     printf("main.c / main : Waiting for client connection\n");
  598.     if (-1 == (iClientSocket = accept(iMasterSocket, NULL, NULL)))
  599.         vCleanExit("main.c / main : accept() error", Errno());
  600.     
  601.     uOpened |= XDC_C_CSOCK;
  602.     
  603.     printf("main.c / main : accept()ed socket %d\n", iClientSocket);
  604.  
  605.     // NegociateProtocolVersion
  606.     printf("main.c / main : Negociating protocol version\n");
  607.     sprintf((char *) mProtVerMsg, rfbProtocolVersionFormat,
  608.     rfbProtocolMajorVersion,
  609.     rfbProtocolMinorVersion);
  610.     if (-1 == (send(iClientSocket, (UBYTE *) mProtVerMsg, sz_rfbProtocolVersionMsg, 0)))
  611.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  612.     
  613.     mProtVerMsg[12] = 0;
  614.  
  615.     if (-1 == (recv(iClientSocket, mProtVerMsg, sz_rfbProtocolVersionMsg, 0)))
  616.     { vCleanSession(XDC_RECV, Errno()); goto _NewSession; }
  617.  
  618.     sscanf((char *) mProtVerMsg, rfbProtocolVersionFormat, &iMajor, &iMinor);
  619.     printf("main.c / main : Protocol supported by server : %d.%d, by client : %d.%d\n", rfbProtocolMajorVersion, rfbProtocolMinorVersion, iMajor, iMinor);
  620.  
  621.     // If major == minor == 0, fake client asks to exit
  622.     if ((!iMajor) && (!iMinor))
  623.         vCleanExit("main.c / main : Exit asked", 0);
  624.         
  625.     // Check protocol version
  626.     if (iMajor > rfbProtocolMajorVersion)
  627.     { vCleanSession("main.c / main : unknown protocol", 0); goto _NewSession; }
  628.     
  629.     // Authenticate DES
  630.     printf("main.c / main : Authentication\n");
  631.     if (FALSE == bAuthentify())
  632.     { vCleanSession("main.c / main : Authenticate error", 0); goto _NewSession; }
  633.     
  634.     // ClientInit
  635.     printf("main.c / main : ClientInitialisation\n");
  636.     if (-1 == (recv(iClientSocket, &c8, sizeof(c8), 0)))
  637.     { vCleanSession(XDC_RECV, Errno()); goto _NewSession; }
  638.     
  639.     printf("main.c / main : SharedFlag = %d (multiple clients : %s)\n", c8, c8 ? "Yes" : "No");
  640.  
  641.     // Grab active screen
  642.     pActiveScreen = IntuitionBase -> FirstScreen;
  643.     printf("main.c / main : Screen set to [%s]\n", pActiveScreen -> Title);
  644.  
  645.     // Grab raster pointer (dirty but EFFICIENT !)
  646.     UnLockBitMap(LockBitMapTags(pActiveScreen -> RastPort.BitMap,
  647.                  LBMI_BASEADDRESS, (ULONG *) &uCnt,
  648.                  TAG_DONE));
  649.     pRaster = (UBYTE *) uCnt;
  650.  
  651.     // Prepare VNC pixel encoding from screen info (if not forced on command line)
  652.     if (GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_ISCYBERGFX)
  653.      && GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_ISLINEARMEM))
  654.     {
  655.         iMode = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_PIXFMT);
  656.         iWidth = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_WIDTH); // X size
  657.         iHeight = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT); // Y size
  658.         iDepth = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_BPPIX); // Bytes / pixel
  659.         printf("main.c / main : RTG mode %s/%ld\nmain.c / main : ", CGXlib ? "CGFx" : "Pic96", iMode);
  660.     }
  661.     else
  662.     { vCleanSession("main.c / main : Screenmode not supported", 0); goto _NewSession; }
  663.  
  664.     iSize = iWidth * iHeight * iDepth; // Actual total byte size of screen raster 
  665.  
  666.     printf("main.c / main : @ 0x%08lX, %dx%d, %d Bpp, size %d\n", pRaster, iWidth, iHeight, iDepth, iSize);    
  667.  
  668.     // Fast mode : 2 byte pixel screens under Picasso96
  669.     bFast = ((!CGXlib) && (iDepth == 2));
  670.     // Allocate pBuffer (reference buffer for screen compare)
  671.     // - with 4 byte / pixel size if under CGFx or Depth >= 3
  672.     // - with just the screen size if under P96 and Depth < 3
  673.     // (to send initial screen)
  674.     if (!(pBuffer = malloc(iWidth * iHeight * (bFast ? iDepth : XDC_C_MAXDEPTH))))
  675.     { vCleanSession("main.c / main : malloc() error", 0); goto _NewSession; }
  676.    
  677.     uOpened |= XDC_C_VBUF;
  678.  
  679.     // ServerInit
  680.     if (bFast)
  681.     {
  682.         switch(iMode)
  683.         {
  684.             case PIXFMT_RGB16PC : // TESTED OK /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggbbbbbrrrrrggg */
  685.                 mSerInitMsg.format.bitsPerPixel = 16;
  686.                 mSerInitMsg.format.depth = 16;
  687.                 mSerInitMsg.format.bigEndian = TRUE;
  688.                 mSerInitMsg.format.trueColour = TRUE;
  689.                 mSerInitMsg.format.redMax = 31;
  690.                 mSerInitMsg.format.greenMax = 63;
  691.                 mSerInitMsg.format.blueMax = 31;
  692.                 mSerInitMsg.format.redShift = 11;
  693.                 mSerInitMsg.format.greenShift = 5;
  694.                 mSerInitMsg.format.blueShift = 0;
  695.                 break;
  696.             case PIXFMT_RGB15PC :        /* HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg */
  697.                 mSerInitMsg.format.bitsPerPixel = 16;
  698.                 mSerInitMsg.format.depth = 15;
  699.                 mSerInitMsg.format.bigEndian = TRUE;
  700.                 mSerInitMsg.format.trueColour = TRUE;
  701.                 mSerInitMsg.format.redMax = 31;
  702.                 mSerInitMsg.format.greenMax = 31;
  703.                 mSerInitMsg.format.blueMax = 31;
  704.                 mSerInitMsg.format.redShift = 10;
  705.                 mSerInitMsg.format.greenShift = 5;
  706.                 mSerInitMsg.format.blueShift = 0;
  707.                 break;
  708.             case PIXFMT_RGB16 :          /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: rrrrrggggggbbbbb */
  709.                 mSerInitMsg.format.bitsPerPixel = 16;
  710.                 mSerInitMsg.format.depth = 16;
  711.                 mSerInitMsg.format.bigEndian = FALSE;
  712.                 mSerInitMsg.format.trueColour = TRUE;
  713.                 mSerInitMsg.format.redMax = 31;
  714.                 mSerInitMsg.format.greenMax = 63;
  715.                 mSerInitMsg.format.blueMax = 31;
  716.                 mSerInitMsg.format.redShift = 11;
  717.                 mSerInitMsg.format.greenShift = 5;
  718.                 mSerInitMsg.format.blueShift = 0;
  719.                 break;
  720.             case PIXFMT_RGB15 :          /* HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb */
  721.                 mSerInitMsg.format.bitsPerPixel = 16;
  722.                 mSerInitMsg.format.depth = 15;
  723.                 mSerInitMsg.format.bigEndian = TRUE;
  724.                 mSerInitMsg.format.trueColour = TRUE;
  725.                 mSerInitMsg.format.redMax = 31;
  726.                 mSerInitMsg.format.greenMax = 31;
  727.                 mSerInitMsg.format.blueMax = 31;
  728.                 mSerInitMsg.format.redShift = 10;
  729.                 mSerInitMsg.format.greenShift = 5;
  730.                 mSerInitMsg.format.blueShift = 0;
  731.                 break;
  732.             case PIXFMT_BGR16PC :        /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggrrrrrbbbbbggg */
  733.                 mSerInitMsg.format.bitsPerPixel = 16;
  734.                 mSerInitMsg.format.depth = 16;
  735.                 mSerInitMsg.format.bigEndian = TRUE;
  736.                 mSerInitMsg.format.trueColour = TRUE;
  737.                 mSerInitMsg.format.redMax = 31;
  738.                 mSerInitMsg.format.greenMax = 63;
  739.                 mSerInitMsg.format.blueMax = 31;
  740.                 mSerInitMsg.format.redShift = 0;
  741.                 mSerInitMsg.format.greenShift = 5;
  742.                 mSerInitMsg.format.blueShift = 11;
  743.                 break;
  744.             case PIXFMT_BGR15PC :        /* HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg */
  745.                 mSerInitMsg.format.bitsPerPixel = 16;
  746.                 mSerInitMsg.format.depth = 15;
  747.                 mSerInitMsg.format.bigEndian = TRUE;
  748.                 mSerInitMsg.format.trueColour = TRUE;
  749.                 mSerInitMsg.format.redMax = 31;
  750.                 mSerInitMsg.format.greenMax = 31;
  751.                 mSerInitMsg.format.blueMax = 31;
  752.                 mSerInitMsg.format.redShift = 0;
  753.                 mSerInitMsg.format.greenShift = 5;
  754.                 mSerInitMsg.format.blueShift = 10;
  755.                 break;
  756.             case PIXFMT_BGR16 :        /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: bbbbbggggggrrrrr */
  757.                 mSerInitMsg.format.bitsPerPixel = 16;
  758.                 mSerInitMsg.format.depth = 16;
  759.                 mSerInitMsg.format.bigEndian = FALSE;
  760.                 mSerInitMsg.format.trueColour = TRUE;
  761.                 mSerInitMsg.format.redMax = 31;
  762.                 mSerInitMsg.format.greenMax = 63;
  763.                 mSerInitMsg.format.blueMax = 31;
  764.                 mSerInitMsg.format.redShift = 0;
  765.                 mSerInitMsg.format.greenShift = 5;
  766.                 mSerInitMsg.format.blueShift = 11;
  767.                 break;
  768.             case PIXFMT_BGR15 :        /* HiColor15 (5 bit each), format: 0bbbbbbgggggrrrrr */
  769.                 mSerInitMsg.format.bitsPerPixel = 16;
  770.                 mSerInitMsg.format.depth = 15;
  771.                 mSerInitMsg.format.bigEndian = FALSE;
  772.                 mSerInitMsg.format.trueColour = TRUE;
  773.                 mSerInitMsg.format.redMax = 31;
  774.                 mSerInitMsg.format.greenMax = 31;
  775.                 mSerInitMsg.format.blueMax = 31;
  776.                 mSerInitMsg.format.redShift = 0;
  777.                 mSerInitMsg.format.greenShift = 5;
  778.                 mSerInitMsg.format.blueShift = 10;
  779.                 break;
  780.             default :
  781.                 { vCleanSession("main.c / main : RGB mode not supported", 0); goto _NewSession; }
  782.                 break;
  783.          }
  784.     }
  785.     else // CGFx ou Depth != 2
  786.     {
  787.         mSerInitMsg.format.bitsPerPixel = 32;
  788.         mSerInitMsg.format.depth = 24;
  789.         mSerInitMsg.format.bigEndian = bBig;
  790.         mSerInitMsg.format.trueColour = TRUE;
  791.         mSerInitMsg.format.redMax =
  792.         mSerInitMsg.format.greenMax =
  793.         mSerInitMsg.format.blueMax = 255;
  794.         mSerInitMsg.format.redShift = iRShift;
  795.         mSerInitMsg.format.greenShift = iGShift;
  796.         mSerInitMsg.format.blueShift = iBShift;
  797.     }
  798.     
  799.     mSerInitMsg.framebufferWidth = iWidth;
  800.     mSerInitMsg.framebufferHeight = iHeight;
  801.     mSerInitMsg.nameLength = sizeof(XDC_ID);
  802.  
  803.     if (-1 == (send(iClientSocket, (UBYTE *) &mSerInitMsg, sizeof(mSerInitMsg), 0)))
  804.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }    
  805.  
  806.     if (-1 == (send(iClientSocket, (UBYTE *) XDC_ID, sizeof(XDC_ID), 0)))
  807.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  808.  
  809.     // Initial Screen update : header...
  810.     mFBUpdMsg.type = rfbFramebufferUpdate;
  811.     mFBUpdMsg.nRects = 1;
  812.     if (-1 == (send(iClientSocket, (UBYTE *) &mFBUpdMsg, sizeof(mFBUpdMsg), 0)))
  813.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  814.     
  815.     // Initial Screen update : 1 rectangle for whole screen...
  816.     mFBRMsg.r.x = 0;
  817.     mFBRMsg.r.y = 0;
  818.     mFBRMsg.r.w = iWidth;
  819.     mFBRMsg.r.h = iHeight;
  820.     mFBRMsg.encoding = rfbEncodingRaw;
  821.  
  822.     if (-1 == (send(iClientSocket, (UBYTE *) &mFBRMsg, sizeof(mFBRMsg), 0)))
  823.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  824.  
  825.     // Copy raster into buffer for send() and for ulterior compares
  826.     if (bFast)
  827.     {
  828.         // simply send raster memory size (as 16 bit pixels)
  829.         memcpy(pBuffer, pRaster, iSize);
  830.         uSize = uLimit < iSize ? uLimit : iSize;
  831.     }
  832.     else
  833.     {
  834.         // We have to make 4 byte pixels out of the raster
  835.         ReadPixelArray(pBuffer,     // Buffer
  836.                0, 0,        // Dest X/Y in buffer
  837.                iWidth * XDC_C_MAXDEPTH,     // Byte width of buffer
  838.                &(pActiveScreen -> RastPort),
  839.                0, 0,         // Source X/Y
  840.                iWidth, iHeight,  // Source w/h
  841.                RECTFMT_ARGB
  842.                );
  843.                    
  844.         uSize = uLimit < iWidth * iHeight * XDC_C_MAXDEPTH ? uLimit : iWidth * iHeight * XDC_C_MAXDEPTH;
  845.     }
  846.  
  847.     // Send buffer (by uLimit packet size if set)
  848.     uCnt = 0;
  849.     while (uCnt < ((bFast) ? iSize : iWidth * iHeight * XDC_C_MAXDEPTH))
  850.     {
  851.         if (-1 == (send(iClientSocket, (UBYTE *) pBuffer + uCnt, uSize, 0)))
  852.         { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  853.      
  854.         uCnt += uSize;
  855.     }
  856.  
  857.     if (!bFast)
  858.     {
  859.         // Reallocate the buffer, resizing it to what's really necessary
  860.         if (!(pBuffer = realloc(pBuffer, iWidth * iHeight * (CGXlib ? iDepth : ((iDepth != 3) ? iDepth : 4)))))
  861.         { vCleanSession("main.c / main : realloc() error", 0); goto _NewSession; }
  862.        
  863.         // Byte copy the screen into the buffer for fast compare
  864.         memcpy(pBuffer, pRaster, iSize);
  865.  
  866.     }
  867.  
  868.     // Preset framebuffer update message X and Y size to XDC_TILE
  869.     mFBRMsg.r.w =
  870.     mFBRMsg.r.h = XDC_TILE;
  871.  
  872.     // Release a key to the client socket so that child process can grab it
  873.     if (-1 == (iDuplicateSocketKey = ReleaseCopyOfSocket(iClientSocket, UNIQUE_ID)))
  874.     { vCleanSession("main.c / main : ReleaseCopyOfSocket() error", Errno()); goto _NewSession; }
  875.     
  876.     // Create incoming messages handling child process
  877.     if (!CreateNewProcTags(
  878.           NP_Entry, vProcessIncomes,
  879.           NP_StackSize, 32000,
  880.           NP_Name, "AmiVNC handler",
  881.           TAG_DONE
  882.        ))
  883.     { vCleanSession("main.c / main : CreateNewProcTags() error", 0); goto _NewSession; }
  884.         
  885.     // While not end of session (by child or by ourself)
  886.     while (!bDie)
  887.     {
  888.     // Search for active screen change
  889.     if (IntuitionBase -> FirstScreen != pActiveScreen)
  890.     {
  891.         // Check if new screen has same geometry as previous one
  892.         if (GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_ISCYBERGFX)
  893.          && GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_ISLINEARMEM)
  894.          && iWidth == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_WIDTH)
  895.          && iHeight == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT)
  896.          && iDepth == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_BPPIX))
  897.         {
  898.             
  899.             // Grab new raster pointer
  900.             pActiveScreen = IntuitionBase -> FirstScreen;
  901.             printf("main.c / main : Screen set to [%s]\n", pActiveScreen -> Title);
  902.             UnLockBitMap(LockBitMapTags(pActiveScreen -> RastPort.BitMap,
  903.                  LBMI_BASEADDRESS, (ULONG *) &uCnt,
  904.                  TAG_DONE));
  905.             pRaster = (UBYTE *) uCnt;
  906.         }
  907.         else
  908.         { vCleanSession("main.c / main : screenmode changed", 0); goto _NewSession; }
  909.     }
  910.                 
  911.     // Search for changes in screen...
  912.     for (jCnt = 0 ; jCnt < iHeight; jCnt += XDC_TILE)
  913.     {
  914.         for (iCnt = 0 ; iCnt < iWidth ; iCnt += XDC_TILE)
  915.         {
  916.             register int iYtile;
  917.             BOOL bChange = FALSE;
  918.     
  919.             for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  920.             {
  921.                 if (memcmp((UBYTE *) (pBuffer) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  922.                    (UBYTE *) (pRaster) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  923.                    XDC_TILE * iDepth))
  924.                 {
  925.                     memcpy((UBYTE *) (pBuffer) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  926.                        (UBYTE *) (pRaster) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  927.                        XDC_TILE * iDepth);
  928.                     bChange = TRUE;
  929.                 }
  930.             }
  931.         
  932.         // If change found, send the tile
  933.         if (bChange)
  934.         {
  935.             if (-1 == (send(iClientSocket, (UBYTE *) &mFBUpdMsg, sizeof(mFBUpdMsg), 0)))
  936.             { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  937.  
  938.             mFBRMsg.r.x = iCnt;
  939.             mFBRMsg.r.y = jCnt;
  940.        
  941.             // Send framebuffer update header
  942.             if (-1 == (send(iClientSocket, (UBYTE *) &mFBRMsg, sizeof(mFBRMsg), 0)))
  943.             { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  944.  
  945.             // Send update data
  946.             if (bFast) // 2 byte pixels under Pic96 : send directly from buffer (2 is idepth)
  947.             {
  948.                 for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  949.                    memcpy(uTile + XDC_TILE * iYtile * 2,
  950.                           pRaster + 2 * (iCnt + (jCnt + iYtile) * iWidth),
  951.                           XDC_TILE * 2);
  952.             
  953.                 // Send framebuffer update pixel data
  954.                 if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0)))
  955.                 { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  956.             }
  957.             else // Make 4 byte pixels out of raster
  958.             {
  959.                 ReadPixelArray(uTile,     // Buffer
  960.                            0, 0,        // Dest X/Y in buffer
  961.                            XDC_TILE * XDC_C_MAXDEPTH,
  962.                            &(pActiveScreen -> RastPort),
  963.                            iCnt, jCnt,         // Source X/Y
  964.                            XDC_TILE, XDC_TILE,  // Source w/h
  965.                            RECTFMT_ARGB
  966.                            );
  967.                         
  968.                 // Send framebuffer update pixel data
  969.                 if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * XDC_C_MAXDEPTH, 0)))
  970.                 { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  971.             }
  972.         }
  973.         }
  974.     }
  975.     }
  976.     
  977.     vCleanSession("main.c / main : Session stop (child stopped)", 0);
  978.     goto _NewSession;
  979. }
  980.